#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/input/mt.h>
#include <linux/input.h>
#include <linux/irqreturn.h>
#include <linux/of_gpio.h>
#include "../../init-input.h"



#define CTP_NAME "gt928"
#define CTP_IRQ_MODE (IRQF_TRIGGER_FALLING)

#define TOUCH_EVENT_DOWN 0x00 /* 按下 */
#define TOUCH_EVENT_UP 0x01 /* 抬起 */
#define TOUCH_EVENT_ON 0x02 /* 移动 */
#define TOUCH_EVENT_RESERVED 0x03 /* 保留 */

#define CTP_CFG_GROUP1                                                                                                                                                                                          \
        {                                                                                                                                                                                                                               \
                0x46, 0x80, 0x07, 0xB0, 0x04, 0x0A, 0x3D, 0x00, 0x01, 0x0A, 0x1E, 0x0F, 0x50, 0x3C, 0x03, 0x04, 0x01, 0x01, \
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1C, 0x1E, 0x14, 0x90, 0x30, 0xAA, 0x32, 0x30, 0x03, 0x15, 0x00,   \
                        0x00, 0x02, 0x03, 0x03, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x27,   \
                        0x3B, 0x94, 0xC5, 0x02, 0x08, 0x00, 0x00, 0x04, 0x8C, 0x28, 0x00, 0x85, 0x2C, 0x00, 0x80, 0x30, 0x00,   \
                        0x7B, 0x34, 0x00, 0x77, 0x38, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   \
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   \
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x11, 0x10,   \
                        0x0F, 0x0E, 0x0D, 0x0C, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   \
                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,   \
                        0x11, 0x12, 0x13, 0x14, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E,   \
                        0x1C, 0x1B, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x01                                \
        }



static const struct regmap_config regmap_config = {
	.reg_bits = 16,
	.val_bits = 8,
    .max_register = 0x819f,
};

struct bl7401_data{
    struct input_dev *input;
    struct i2c_client *client;
    struct regmap	*regmap;
    struct mutex i2c_lock;	
	int irq_gpio;
	int reset_gpio;
	u32 x_max;
	u32 y_max;
	u32 num_max;     //触摸点上限
	u32 xy_flag; 	//xy轴交换
	struct task_struct *task;
};




static void btl_touch_down(struct bl7401_data* ts,s32 id,s32 x,s32 y,s32 w, s8 pressure)
{	
	input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
	input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, w);
	input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, w);
	input_report_abs(ts->input, ABS_MT_POSITION_X, x);
	input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
	input_report_key(ts->input, BTN_TOUCH, 1);
	input_mt_sync(ts->input);

}


//static void btl_touch_up(struct bl7401_data* ts, s32 id, s32 x,s32 y)
//{

//    input_mt_slot(ts->input, id);
//    input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);

//}


static void bl7401_update_data(struct bl7401_data *bl)
{
	u8 config_data;
	u8 point_data[80] = {0};
    int ret;
    u8  touch_num = 0;
	u8  pressure = 0x0;
//	u16 x_core;    //x分辨率
//	u16 y_core;	   //x分辨率
    s32 input_x = 0;
    s32 input_y = 0;
    s32 input_w = 0;
    s32 id = 0;
//    u8  eventFlag = 0;
    int i;


	ret = regmap_bulk_read(bl->regmap, 0x814E, &config_data, 1);
    if (ret < 0) {
        printk("use I2C reading time from RTC failed with err:%d\n", ret);
        return;
    }
	if(config_data == 0x00)
		return;
	
	if(config_data == 0x80)
		goto exit_work_func;
	

    touch_num = config_data & 0x0f;
    if (touch_num > bl->num_max)
    {
        goto exit_work_func;
    }
	
	if(touch_num > 1 || touch_num == 1)
	{
		regmap_bulk_write(bl->regmap, 0x814F, point_data, touch_num * 8);
	}


	if (touch_num) {
		for (i = 0; i < touch_num; i++) {
			id = point_data[i * 8] & 0x0F;
			input_x = point_data[i * 8 + 1] | (point_data[i * 8 + 2] << 8);
			input_y = point_data[i * 8 + 3] | (point_data[i * 8 + 4] << 8);
			input_w = point_data[i * 8 + 5] | (point_data[i * 8 + 6] << 8);
		}
		btl_touch_down(bl, id, input_x, input_y, input_w, pressure);
	}
	
	input_sync(bl->input);

exit_work_func:
	regmap_write(bl->regmap, 0x814E, 0x00);
	return;
	
}



/*中断函数*/
static irqreturn_t bl7401_handler(int irq, void *dev_id)
{


    struct bl7401_data *bl = (struct bl7401_data*)dev_id;
	printk("bl7401_handler\n");

    /*线程化加锁*/
    mutex_lock(&bl->i2c_lock);
	bl7401_update_data(bl);
	mutex_unlock(&bl->i2c_lock);
	return IRQ_HANDLED;
}



static int device_init(struct bl7401_data* bl)
{
	int ret;
	int i;
	struct i2c_client *client = bl->client;
	u8 config_data[186] = CTP_CFG_GROUP1;
	u8 check_sum = 0;
	
	//set addr
	bl->reset_gpio = of_get_named_gpio(client->dev.of_node, "ctp_reset", 0);
	if (!gpio_is_valid(bl->reset_gpio)) 
    {
          printk("Failed to get bl reset gpio\n");
          return bl->reset_gpio;
    }
	ret = gpio_request(bl->reset_gpio, "gt_reset");
    if (ret < 0)
    {
        printk("request gpio fiiled\n");
        return ret;
    }
	gpio_direction_output(bl->reset_gpio, 1);


	bl->irq_gpio = of_get_named_gpio(client->dev.of_node, "ctp_int_port", 0);
	if (!gpio_is_valid(bl->irq_gpio)) 
	{
			printk("Failed to get bl interrupt gpio\n");
			return bl->irq_gpio;
	}
	ret = gpio_request(bl->irq_gpio, "gt928_interrupt");
	if (ret < 0)
	{
		printk("request gpio fiiled\n");
		return ret;
	}
//	gpio_direction_output(bl->irq_gpio, 1);
//	udelay(200);
//	gpio_set_value(bl->reset_gpio, 1);
//	mdelay(10);
	gpio_direction_input(bl->irq_gpio);

	//gt928 init
	ret = of_property_read_u32(client->dev.of_node, "ctp_screen_max_x", &bl->x_max);
	if (ret){
		printk("get ctp_screen_max_x is fail, %d\n", ret);
	} else {
		config_data[1] = bl->x_max;
		config_data[2] = bl->x_max >> 8;
		printk("config_data[1] = 0x%x, config_data[2] = 0x%x\n",config_data[1],config_data[2]);
	}
	ret = of_property_read_u32(client->dev.of_node, "ctp_screen_max_y", &bl->y_max);
	if (ret) {
		printk("get ctp_screen_max_y is fail, %d\n", ret);
	} else {
		config_data[3] = bl->y_max; 
		config_data[4] = bl->y_max >> 8;
		printk("config_data[2] = 0x%x, config_data[3] = 0x%x\n",config_data[2],config_data[3]);
	}
	ret = of_property_read_u32(client->dev.of_node, "ctp_xy_flag", &bl->xy_flag);
	if (ret) {
		printk("get ctp_xy_flag is fail, %d\n", ret);
	} else {
		if(bl->xy_flag == 1)
			config_data[6] = config_data[6] | (1 << 3);
		else if(bl->xy_flag == 0)
			config_data[6] = config_data[6] & ~(1 << 3);
		printk("config_data[6] = 0x%x\n",config_data[6]);
	}
	ret = of_property_read_u32(client->dev.of_node, "ctp_touch_num_max", &bl->num_max);
	if (ret) {
		printk("get ctp_touch_num_max is fail, %d\n", ret);
	} else {
		config_data[5] = bl->num_max;
		printk("config_data[5] = 0x%x\n",config_data[5]);
	}


    for (i = 0; i < 184; i++) {
                check_sum += config_data[i];
        }
    config_data[184] = (~check_sum) + 1;
	printk("config_data[184] = 0x%x\n",config_data[184]);

	//soft reset
	ret = regmap_write(bl->regmap, 0x8040, 0x02);
	//set version a	
	ret = regmap_write(bl->regmap, 0x8047, 0x00);

	//send config
	ret = regmap_bulk_write(bl->regmap, 0x8047, config_data, 186);

	//end
	ret = regmap_write(bl->regmap, 0x8040, 0x00);
	if(ret)
		printk("addr error\n");
	
	return 0;
}


static int kthread_fun(void *data)
{
//	struct bl7401_data *bl = data;

	while (!kthread_should_stop()) {
		
//		   mutex_lock(&bl->i2c_lock);
//		   bl7401_update_data(bl);
//		   mutex_unlock(&bl->i2c_lock);
           printk("kthread is running\n");
           msleep(1000);
    }

	return 0;
}


static int bl7401_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    struct bl7401_data *bl;
	u8 config[10];

	printk("probe status\n");
    //config_info.node = client->dev.of_node;
    /*申请空间*/
    bl = devm_kzalloc(&client->dev, sizeof(*bl), GFP_KERNEL);
    if(!bl)
    {
        dev_err(&client->dev, "device memory request failed\n");
		return -ENOMEM;
    }

    mutex_init(&bl->i2c_lock);
	bl->regmap = devm_regmap_init_i2c(client, &regmap_config);
	if (IS_ERR(bl->regmap)) 
    {
		dev_err(&client->dev, "I2C initialization regmap failed\n");
		return PTR_ERR(bl->regmap);
	}

    i2c_set_clientdata(client, bl);

	printk("init status\n");
    /*AW 初始化IC，引脚，上电*/
	bl->client = client;

    if (device_init(bl) < 0) 
    {
		printk("can not startup device!\n");
        return -1;
    }

	printk("test\n");
	regmap_bulk_read(bl->regmap, 0x8047, config, 10);
	printk("0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", config[0],config[1],config[2],config[3],config[4],config[5],config[6],config[7],config[8],config[9]);


    printk("starus request irq\n");
    ret = devm_request_threaded_irq(&client->dev, gpio_to_irq(bl->irq_gpio), NULL, bl7401_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, bl);
    if (ret < 0)
    {
        printk("Failed to request touchscreen IRQ.\n");
        return ret;
    }


    /*ME input设备申请与初始化*/
    bl->client = client;
    bl->input = devm_input_allocate_device(&client->dev);
    if (bl->input == NULL) 
    {
        printk("Failed to allocate input device.\n");
        return -1;
    }

    bl->input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    bl->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    __set_bit(INPUT_PROP_DIRECT, bl->input->propbit);

    input_set_abs_params(bl->input, ABS_MT_POSITION_X, 0, bl->x_max, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_POSITION_Y, 0, bl->y_max, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
    input_set_abs_params(bl->input, ABS_MT_TRACKING_ID, 0, bl->num_max, 0, 0);

    bl->input->name = "gt928";
    bl->input->phys = "input/ts";
    bl->input->id.bustype = BUS_I2C;
    bl->input->id.vendor = 0xDEAD;
    bl->input->id.product = 0xBEEF;
    bl->input->id.version = 10427;
    /*注册 input_dev */
    ret = input_register_device(bl->input);
    if(ret)
        return ret;

	
	

	bl->task = kthread_create(kthread_fun, bl, "read_ctp_status");

	if (!bl->task) {
                printk("kthread_run failed!\n");
                return -1;
   }

	printk("input register\n");
    return 0;
}

static int bl7401_remove(struct i2c_client *client)
{
    struct bl7401_data *bl = i2c_get_clientdata(client);
    input_unregister_device(bl->input);
	gpio_free(bl->irq_gpio);
    return 0;
}

static const struct of_device_id bl7401_of_match[] = {
	{.compatible = "gt928"},
	{},
};

static struct i2c_driver bl7401_driver = {
	.probe = bl7401_probe,
	.remove = bl7401_remove,
	.driver = {
        .name = CTP_NAME,
		.owner = THIS_MODULE,
		.of_match_table = bl7401_of_match,
    }
};  

static int __init bl7401_init(void)
{
    printk("gt928 driver init func\n");
	i2c_add_driver(&bl7401_driver);
    return 0;
}

static void __exit bl7401_exit(void)
{
	printk("gt928 driver exited\n");
	i2c_del_driver(&bl7401_driver);
}


late_initcall(bl7401_init);
module_exit(bl7401_exit);


MODULE_LICENSE("GPL");
